package com.xxg.renrenorder.dao;

import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Indexes;
import com.xxg.renrencommon.domain.filedenum.orderenum.AfterSalesOrderStatusEnum;
import com.xxg.renrencommon.domain.filedenum.orderenum.PaymentTypeEnum;
import com.xxg.renrenorder.dao.bean.AfterSalesOrderInfo;
import com.xxg.renrenorder.dao.bean.AfterSalesStep;
import com.xxg.renrenorder.dao.bean.ExpressInfo;
import com.xxg.renrenorder.domain.query.VerifyOrderQuery;
import com.xxg.renrenorder.domain.result.ReFundResult;
import com.xxg.renrenorder.util.OrderIdGenerator;
import org.bson.Document;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Set;

import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
import static org.springframework.data.mongodb.core.query.Criteria.where;

/**
 * 售后订单Dao
 *
 * @author xxg
 * @date 2020/11/16
 */
@Repository
public class AfterSalesOrderInfoDao {
    private final MongoTemplate mongoTemplate;
    private final OrderIdGenerator orderIdGenerator;

    public AfterSalesOrderInfoDao(MongoTemplate mongoTemplate, OrderIdGenerator orderIdGenerator) {
        this.mongoTemplate = mongoTemplate;
        this.orderIdGenerator = orderIdGenerator;
        createCollection();
    }

    /**
     * 创建collection
     */
    private void createCollection() {
        String collectionName = "afterSalesOrderInfo";
        MongoCollection<Document> collection;
        if (!mongoTemplate.getCollectionNames().contains(collectionName)) {
            collection = mongoTemplate.createCollection(AfterSalesOrderInfo.class);
            createIndex(collection);
        }
    }

    /**
     * 创建索引
     *
     * @param collection 数据集
     */
    private void createIndex(MongoCollection<Document> collection) {
        collection.createIndex(Indexes.compoundIndex(Indexes.ascending("userId"),
                Indexes.ascending("status")));
        collection.createIndex(Indexes.descending("createTime"));
        collection.createIndex(Indexes.ascending("status"));
        collection.createIndex(Indexes.compoundIndex(Indexes.ascending("orderId"),
                Indexes.ascending("skuId")));
        collection.createIndex(Indexes.compoundIndex(Indexes.ascending("orderId"),
                Indexes.ascending("status")));
    }

    /**
     * 分页获取特定用户售后订单
     *
     * @param userId   会员ID
     * @param pageNo   页码
     * @param pageSize 页大小
     * @return 售后订单列表
     */
    public List<AfterSalesOrderInfo> getAfterSalesOrdersByUserId(String userId, Integer pageNo, Integer pageSize) {
        int start = pageNo * pageSize;
        Query query = new Query(where("userId").is(userId).and("deleted").is(null));
        query.with(Sort.by(Sort.Order.desc("createTime")));
        query.skip(start).limit(pageSize);
        return mongoTemplate.find(query, AfterSalesOrderInfo.class);
    }

    /**
     * 统计出正在处理的售后订单数量
     *
     * @param userId 会员ID
     * @return 数量
     */
    public int getUnFinishOrderCount(String userId) {
        Query query = new Query(where("userId").is(userId).and("status").nin(3, 4, 8, 9, 12, 15, 17, 19));
        return (int) mongoTemplate.count(query, AfterSalesOrderInfo.class);
    }

    /**
     * 根据ID查询售后订单详情
     *
     * @param id 订单ID
     * @return 售后订单详情
     */
    public AfterSalesOrderInfo getOrderByOrderId(String id) {
        Query query = new Query(where("_id").is(id));
        return mongoTemplate.findOne(query, AfterSalesOrderInfo.class);
    }

    /**
     * 根据ID删除用户自己的售后订单
     *
     * @param id     订单ID
     * @param userId 会员ID
     */
    public void removeAfterSalesOrderById(String id, Integer userId) {
        // 处于结束状态的售后订单可删除
        Query query = new Query(where("_id").is(id).and("userId").is(userId)
                .and("status").in(AfterSalesOrderStatusEnum.RETURNED_PAID.getValue(), AfterSalesOrderStatusEnum.CANCEL.getValue(),
                        AfterSalesOrderStatusEnum.REJECTED.getValue(), AfterSalesOrderStatusEnum.CLOSED.getValue()));
        Update update = new Update();
        update.set("deleted", true);
        update.set("updateTime", new Date());
        mongoTemplate.updateFirst(query, update, AfterSalesOrderInfo.class);
    }

    /**
     * 根据状态分页获取所有用户的售后订单
     *
     * @param orderStatus    订单状态
     * @param pageNo         页码
     * @param pageSize       页大小
     * @param dates          开始日期结束日期
     * @param hasClickReFund 已经点击退款 true-已点击
     * @param spuName
     * @return 结果
     */
    public List<AfterSalesOrderInfo> getAllAfterSalesOrdersByStatus(List<Integer> orderStatus, Integer pageNo, Integer pageSize, Date[] dates, Boolean hasClickReFund, String spuName) {
        int start = pageNo * pageSize;
        Query query = new Query();
        if (orderStatus != null) {
            query = new Query(where("status").in(orderStatus));
        }
        if (dates != null) {
            Criteria criteria = new Criteria();
            criteria.and("createTime").gte(dates[0]).lte(dates[1]);
            query.addCriteria(criteria);
        }
        if (hasClickReFund != null && hasClickReFund) {
            Criteria criteria = new Criteria();
            criteria.and("hasClickReFund").is(true);
            query.addCriteria(criteria);
        } else if (hasClickReFund != null) {
            Criteria criteria = new Criteria();
            criteria.and("hasClickReFund").ne(true);
            query.addCriteria(criteria);
        }
        if (spuName != null && spuName.trim().length() > 0) {
            query.addCriteria(where("productInfo.spuName").regex(spuName));
        }
        query.with(Sort.by(Sort.Order.desc("createTime")));
        query.skip(start).limit(pageSize);
        return mongoTemplate.find(query, AfterSalesOrderInfo.class);
    }

    public long countAllAfterSalesOrdersByStatus(List<Integer> orderStatus, Date[] dates, Boolean hasClickReFund, String spuName) {
        Query query = new Query();
        if (orderStatus != null) {
            query = new Query(where("status").in(orderStatus));
        }
        if (dates != null) {
            Criteria criteria = new Criteria();
            criteria.and("createTime").gte(dates[0]).lte(dates[1]);
            query.addCriteria(criteria);
        }
        if (hasClickReFund != null && hasClickReFund) {
            Criteria criteria = new Criteria();
            criteria.and("hasClickReFund").is(true);
            query.addCriteria(criteria);
        } else if (hasClickReFund != null) {
            Criteria criteria = new Criteria();
            criteria.and("hasClickReFund").ne(true);
            query.addCriteria(criteria);
        }
        if (spuName != null && spuName.trim().length() > 0) {
            query.addCriteria(where("productInfo.spuName").regex(spuName));
        }
        query.with(Sort.by(Sort.Order.desc("createTime")));
        return mongoTemplate.count(query, AfterSalesOrderInfo.class);
    }

    /**
     * 提交售后申请
     *
     * @param afterSalesOrderInfo 售后申请信息
     */
    public void applyAfterSalesOrder(AfterSalesOrderInfo afterSalesOrderInfo) {
        long id = orderIdGenerator.createId();
        afterSalesOrderInfo.setId(String.valueOf(id));
        afterSalesOrderInfo.setCreateTime(new Date());
        // 未审核状态
        afterSalesOrderInfo.setStatus(AfterSalesOrderStatusEnum.UN_VERIFY.getValue());
        mongoTemplate.insert(afterSalesOrderInfo);
    }

    /**
     * 更新售后订单
     *
     * @param afterSalesOrderInfo 售后订单
     */
    public void saveAfterSalesOrder(AfterSalesOrderInfo afterSalesOrderInfo) {
        mongoTemplate.save(afterSalesOrderInfo);
    }

    /**
     * 取消售后申请
     *
     * @param id     售后订单ID
     * @param userId 会员ID
     * @return 结果
     */
    public AfterSalesOrderInfo cancelAfterSalesOrder(String id, String userId) {
        // 处于待审核的售后申请才能取消
        Query query = new Query(where("_id").is(id).and("userId").is(userId)
                .and("status").in(AfterSalesOrderStatusEnum.UN_VERIFY.getValue()));
        Update update = new Update();
        update.set("updateTime", new Date());
        update.set("status", AfterSalesOrderStatusEnum.CANCEL.getValue());
        return mongoTemplate.findAndModify(query, update, AfterSalesOrderInfo.class);
    }

    /**
     * 检查是否已申请售后
     *
     * @param orderId 订单ID
     * @param skuId   商品ID
     * @return true-已申请，false-未申请
     */
    public boolean hasOrder(String orderId, String skuId) {
        Query query = new Query(where("orderId").is(orderId).and("skuId").is(skuId));
        return mongoTemplate.count(query, AfterSalesOrderInfo.class) > 0;
    }

    /**
     * 审核售后申请
     *
     * @param verifyOrderQuery 审核信息
     * @return 结果
     */
    public AfterSalesOrderInfo verifyAfterSalesOrder(VerifyOrderQuery verifyOrderQuery, AfterSalesOrderInfo afterSalesOrderInfo) {
        Query query = new Query(where("_id").is(verifyOrderQuery.getId()));
        Update update = new Update();
        update.set("status", verifyOrderQuery.getStatus());
        update.set("updateTime", new Date());
        update.set("response", verifyOrderQuery.getResponse());
        update.set("verifyType", verifyOrderQuery.getVerifyType());
        update.set("verifyRemark", verifyOrderQuery.getVerifyRemark());
        update.set("lessQuantity", verifyOrderQuery.getLessQuantity());
        update.set("afterSalesSteps", afterSalesOrderInfo.getAfterSalesSteps());
        update.set("backExpressInfo", afterSalesOrderInfo.getBackExpressInfo());
        if (afterSalesOrderInfo.getAfterSalesType() == 1 && afterSalesOrderInfo.getReasonType() == 6) {
            update.set("refundReason", afterSalesOrderInfo.getRefundReason());
            update.set("realReturnPay", afterSalesOrderInfo.getRealReturnPay());
        }
        return mongoTemplate.findAndModify(query, update, AfterSalesOrderInfo.class);
    }

    /**
     * 设置已收到货状态
     *
     * @param id 售后订单ID
     * @return 结果
     */
    public AfterSalesOrderInfo updateAfterSalesOrderStatus(String id) {
        Query query = new Query(where("_id").is(id).and("status").is(AfterSalesOrderStatusEnum.UN_RETURN_EXPRESS.getValue()));
        Update update = new Update();
        update.set("updateTime", new Date());
        update.set("status", AfterSalesOrderStatusEnum.RETURNING_PAID.getValue());
        return mongoTemplate.findAndModify(query, update, AfterSalesOrderInfo.class);
    }

    /**
     * 设置已退款状态
     *
     * @param id     售后订单ID
     * @param status 订单状态
     */
    public void setAfterSalesOrderStatus(String id, Integer status) {
        Query query = new Query(where("_id").is(id).and("status").in(AfterSalesOrderStatusEnum.RETURNING_PAID.getValue(),
                AfterSalesOrderStatusEnum.RETURN_REFUND.getValue()));
        Update update = new Update();
        update.set("updateTime", new Date());
        update.set("status", status);
        mongoTemplate.updateFirst(query, update, AfterSalesOrderInfo.class);
    }

    /**
     * 设置退款
     *
     * @param id 售后订单ID
     * @return 结果
     */
    public AfterSalesOrderInfo finishAfterSalesOrder(String id, ReFundResult response) {
        Query query = new Query(where("_id").is(id).and("status").in(AfterSalesOrderStatusEnum.RETURNING_PAID.getValue(),
                AfterSalesOrderStatusEnum.RETURN_REFUND.getValue()));
        Update update = new Update();
        update.set("updateTime", new Date());
        // 支付宝退款或卡退款直接返回，微信需要等待通知
        if (response.getPaymentType() == PaymentTypeEnum.ALIPAY.getValue()
                || response.getPaymentType() == PaymentTypeEnum.CARD_PAY.getValue()) {
            update.set("status", AfterSalesOrderStatusEnum.RETURNED_PAID.getValue());
        }
        update.set("paymentInfo.paymentType", response.getPaymentType());
        update.set("paymentInfo.gmtPayment", response.getGmtPayment());
        update.set("paymentInfo.tradeNo", response.getTradeNo());
        update.set("paymentInfo.totalAmount", response.getTotalAmount());
        update.set("hasClickReFund", true);
        // 添加退款里程碑
        AfterSalesStep afterSalesStep = new AfterSalesStep();
        afterSalesStep.setCreateTime(new Date());
        afterSalesStep.setDescription("平台：已退款；退款金额：" + response.getTotalAmount());
        afterSalesStep.setRole(1);
        update.push("afterSalesSteps", afterSalesStep);
        return mongoTemplate.findAndModify(query, update, AfterSalesOrderInfo.class);
    }

    /**
     * 根据购物订单号查询所有售后订单已完成退款总数
     *
     * @param orderId 购物订单号
     * @return 售后订单已完成退款总数
     */
    public int getReturnedPaidAfterSalesOrderCount(String orderId) {
        Query query = new Query(where("orderId").is(orderId).and("status").is(AfterSalesOrderStatusEnum.RETURNED_PAID.getValue()));
        return (int) mongoTemplate.count(query, AfterSalesOrderInfo.class);
    }

    /**
     * 更新售后订单的物流信息
     *
     * @param userId          会员ID
     * @param id              售后订单ID
     * @param expressInfo     物流信息
     * @param afterSalesSteps 里程碑节点信息
     */
    public void updateExpress(String userId, String id, List<ExpressInfo> expressInfo, List<AfterSalesStep> afterSalesSteps) {
        Query query = new Query(where("_id").is(id).and("userId").is(userId));
        Update update = new Update();
        update.set("updateTime", new Date());
        update.set("expressInfo", expressInfo);
        update.set("afterSalesSteps", afterSalesSteps);
        mongoTemplate.updateFirst(query, update, AfterSalesOrderInfo.class);
    }

    /**
     * 根据条件查询售后订单数量
     *
     * @param orderStatus 订单状态
     * @param dates       开始日期结束日期
     * @return 数量
     */
    public int getAllAfterSalesOrdersCountByStatus(List<Integer> orderStatus, Date[] dates) {
        Query query = new Query();
        if (orderStatus != null) {
            query = new Query(where("status").in(orderStatus));
        }
        if (dates != null) {
            Criteria criteria = new Criteria();
            criteria.and("createTime").gte(dates[0]).lte(dates[1]);
            query.addCriteria(criteria);
        }
        return (int) mongoTemplate.count(query, AfterSalesOrderInfo.class);
    }

    /**
     * 更新售后订单扣款、运费差价信息
     *
     * @param afterSalesOrderInfo 售后订单信息
     */
    public void updateRefunds(AfterSalesOrderInfo afterSalesOrderInfo) {
        Query query = new Query(where("_id").is(afterSalesOrderInfo.getId()));
        Update update = new Update();
        update.set("updateTime", new Date());
        update.set("cutPayment", afterSalesOrderInfo.getCutPayment());
        update.set("offsetExpressFee", afterSalesOrderInfo.getOffsetExpressFee());
        update.set("refundReason", afterSalesOrderInfo.getRefundReason());
        update.set("realReturnPay", afterSalesOrderInfo.getRealReturnPay());
        mongoTemplate.updateFirst(query, update, AfterSalesOrderInfo.class);
    }

    /**
     * 查询正在处理的售后订单(具体商品)数量
     *
     * @param id    订单ID
     * @param skuId 商品id
     * @return 结果
     */
    public long getUnFinishOrderCountByOrderId(String id, Integer skuId) {
        Query query = new Query(where("orderId").is(id).and("productInfo.skuId").is(skuId).and("status").in(0, 1, 2));
        return mongoTemplate.count(query, AfterSalesOrderInfo.class);
    }

    /**
     * 根据售后类型和具体商品查询是否存在被永久拒绝的售后订单
     *
     * @param id             订单ID
     * @param afterSalesType 售后类型
     * @param skuId          商品id
     * @return 结果
     */
    public boolean hasForeverRejectedOrderByType(String id, Integer afterSalesType, Integer skuId) {
        Query query = new Query(where("orderId").is(id).and("afterSalesType").is(afterSalesType).and("productInfo.skuId").is(skuId)
                .and("status").is(AfterSalesOrderStatusEnum.REJECTED_FOREVER.getValue()));
        return mongoTemplate.count(query, AfterSalesOrderInfo.class) > 0;
    }

    /**
     * 检查具体商品是否已经处理过仅退款(协商退款)请求
     *
     * @param id    订单ID
     * @param skuId 商品id
     * @return 结果
     */
    public boolean hasDoneBeforeOrderByType(String id, Integer skuId) {
        Query query = new Query(where("orderId").is(id).and("afterSalesType").is(1).and("reasonType").is(6).and("productInfo.skuId").is(skuId)
                .and("status").is(AfterSalesOrderStatusEnum.RETURNED_PAID.getValue()));
        return mongoTemplate.count(query, AfterSalesOrderInfo.class) > 0;
    }

    /**
     * 根据订单号查询所有关联的售后订单
     *
     * @param id 订单ID
     * @return 结果
     */
    public List<AfterSalesOrderInfo> getRelatedOrdersByOrderId(String id) {
        Query query = new Query(where("orderId").is(id));
        query.with(Sort.by(Sort.Order.desc("createTime")));
        return mongoTemplate.find(query, AfterSalesOrderInfo.class);
    }

    /**
     * 查询是否处理过其他的售后申请
     *
     * @param id    订单ID
     * @param skuId 商品id
     * @return 结果
     */
    public boolean hasDoneOtherAfterSales(String id, Integer skuId) {
        Query query = new Query(where("orderId").is(id)
                .and("productInfo.skuId").is(skuId)
                .and("afterSalesType").in(4, 5, 6, 7)
                .and("status").in(AfterSalesOrderStatusEnum.FINISH_REPAIR.getValue(),
                        AfterSalesOrderStatusEnum.FINISH_REPLENISHMENT.getValue(),
                        AfterSalesOrderStatusEnum.FINISH_REPLENISHMENT_PART.getValue(),
                        AfterSalesOrderStatusEnum.FINISH_CHANGE.getValue()));
        return mongoTemplate.count(query, AfterSalesOrderInfo.class) > 0;
    }

    /**
     * 设置退款比例
     *
     * @param id          售后id
     * @param reFundRatio 退款比例
     */
    public void setReFundRatio(String id, BigDecimal reFundRatio) {
        Query query = new Query(where("_id").is(id));
        Update update = new Update();
        update.set("reFundRatio", reFundRatio);
        mongoTemplate.updateFirst(query, update, AfterSalesOrderInfo.class);
    }
}
